package com.macro.mall.storage;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.macro.mall.common.enums.SourceTypeEnum;
import com.macro.mall.dto.BucketPolicyConfigDto;
import com.macro.mall.dto.StorageObject;
import io.minio.*;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;

import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.stream.Stream;

/**
 * @author 郎
 */
public class MinioStorage implements Storage {

    private final Log logger = LogFactory.getLog(MinioStorage.class);

    @Getter
    @Setter
    private String endpoint;
    @Getter
    @Setter
    private String accessKey;
    @Getter
    @Setter
    private String secretKey;
    @Getter
    @Setter
    private String bucketName;

    /**
     * 七牛云OSS对象存储简单上传实现
     */
    @Override
    public StorageObject store(InputStream inputStream, long contentLength, String contentType, String keyName) {
        try {
            //创建一个MinIO的Java客户端
            MinioClient minioClient = MinioClient.builder()
                                                 .endpoint(endpoint)
                                                 .credentials(accessKey, secretKey)
                                                 .build();
            boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (isExist) {
                logger.info("存储桶已经存在！");
            } else {
                //创建存储桶并设置只读权限
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
                BucketPolicyConfigDto bucketPolicyConfigDto = createBucketPolicyConfigDto(bucketName);
                SetBucketPolicyArgs setBucketPolicyArgs = SetBucketPolicyArgs.builder()
                                                                             .bucket(bucketName)
                                                                             .config(JSONUtil.toJsonStr(bucketPolicyConfigDto))
                                                                             .build();
                minioClient.setBucketPolicy(setBucketPolicyArgs);
            }
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            // 设置存储对象名称
            String objectName = sdf.format(new Date()) + "/" + keyName;
            // 使用putObject上传一个文件到存储桶中
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                                                       .bucket(bucketName)
                                                       .object(objectName)
                                                       .contentType(contentType)
                                                       .stream(inputStream, contentLength, ObjectWriteArgs.MIN_MULTIPART_SIZE).build();
            minioClient.putObject(putObjectArgs);
            logger.info("文件上传成功!");
            return new StorageObject(endpoint + "/" + bucketName + "/" + objectName, keyName, objectName, contentType, contentLength, SourceTypeEnum.MINIO.getCode());
        } catch (Exception e) {
            logger.error("上传发生错误: " + e.getMessage(), e);
        }
        return null;
    }

    private BucketPolicyConfigDto createBucketPolicyConfigDto(String bucketName) {
        BucketPolicyConfigDto.Statement statement = BucketPolicyConfigDto.Statement.builder()
                                                                                   .Effect("Allow")
                                                                                   .Principal("*")
                                                                                   .Action("s3:GetObject")
                                                                                   .Resource("arn:aws:s3:::" + bucketName + "/*.**").build();
        return BucketPolicyConfigDto.builder()
                                    .Version("2012-10-17")
                                    .Statement(CollUtil.toList(statement))
                                    .build();
    }

    @Override
    public Stream<Path> loadAll() {
        return null;
    }

    @Override
    public Path load(String keyName) {
        return null;
    }

    @Override
    public Resource loadAsResource(String keyName) {
        try {
            URL url = new URL(generateUrl(keyName));
            Resource resource = new UrlResource(url);
            if (resource.exists() || resource.isReadable()) {
                return resource;
            } else {
                return null;
            }
        } catch (MalformedURLException e) {
            logger.error("加载数据发生错误: " + e.getMessage(), e);
            return null;
        }
    }

    @Override
    public void delete(String keyName) {
        try {
            MinioClient minioClient = MinioClient.builder()
                                                 .endpoint(endpoint)
                                                 .credentials(accessKey, secretKey)
                                                 .build();
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(keyName).build());
        } catch (Exception e) {
            logger.error("删除文件发生错误: " + e.getMessage(), e);
        }
    }

    @Override
    public String generateUrl(String keyName) {
        return endpoint + "/" + keyName;
    }
}
